package com.zenithmind.exam.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.exam.mapper.ExamParticipantMapper;
import com.zenithmind.exam.pojo.entity.ExamParticipant;
import com.zenithmind.exam.service.ExamParticipantService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 考试参与者服务实现类
 * 
 * @author ZenithMind
 * @since 2024-07-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExamParticipantServiceImpl extends ServiceImpl<ExamParticipantMapper, ExamParticipant> implements ExamParticipantService {

    private final ExamParticipantMapper examParticipantMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addParticipant(String examId, String userId, String userName) {
        try {
            // 检查是否已经是参与者
            ExamParticipant existing = examParticipantMapper.selectByExamIdAndUserId(examId, userId);
            if (existing != null) {
                if (existing.getStatus() == 1) {
                    throw new BusinessException("用户已经是考试参与者");
                } else {
                    // 如果之前被禁止，现在重新启用
                    existing.setStatus(1);
                    existing.setJoinTime(LocalDateTime.now());
                    return updateById(existing);
                }
            }

            ExamParticipant participant = new ExamParticipant();
            participant.setExamId(examId);
            participant.setUserId(userId);
            participant.setUserName(userName);
            participant.setStatus(1); // 允许参与
            participant.setInviteTime(LocalDateTime.now());
            participant.setJoinTime(LocalDateTime.now());
            participant.setCreateBy(UserContext.getUserId());
            participant.setCreateTime(LocalDateTime.now());

            boolean result = save(participant);
            if (result) {
                log.info("添加考试参与者成功，考试ID: {}, 用户ID: {}", examId, userId);
            }
            return result;
        } catch (Exception e) {
            log.error("添加考试参与者失败", e);
            throw new BusinessException("添加考试参与者失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchAddParticipants(String examId, List<String> userIds) {
        try {
            List<ExamParticipant> participants = userIds.stream()
                    .map(userId -> {
                        // 检查是否已存在
                        ExamParticipant existing = examParticipantMapper.selectByExamIdAndUserId(examId, userId);
                        if (existing != null && existing.getStatus() == 1) {
                            return null; // 已存在且状态正常，跳过
                        }

                        ExamParticipant participant = new ExamParticipant();
                        participant.setExamId(examId);
                        participant.setUserId(userId);
                        participant.setUserName(""); // 用户名可以后续补充
                        participant.setStatus(1);
                        participant.setInviteTime(LocalDateTime.now());
                        participant.setJoinTime(LocalDateTime.now());
                        participant.setCreateBy(UserContext.getUserId());
                        participant.setCreateTime(LocalDateTime.now());
                        return participant;
                    })
                    .filter(participant -> participant != null)
                    .collect(Collectors.toList());

            if (participants.isEmpty()) {
                return true; // 没有需要添加的参与者
            }

            int result = examParticipantMapper.batchInsert(participants);
            if (result > 0) {
                log.info("批量添加考试参与者成功，考试ID: {}, 添加数量: {}", examId, result);
            }
            return result > 0;
        } catch (Exception e) {
            log.error("批量添加考试参与者失败", e);
            throw new BusinessException("批量添加考试参与者失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeParticipant(String examId, String userId) {
        try {
            ExamParticipant participant = examParticipantMapper.selectByExamIdAndUserId(examId, userId);
            if (participant == null) {
                throw new BusinessException("参与者不存在");
            }

            boolean result = removeById(participant.getId());
            if (result) {
                log.info("移除考试参与者成功，考试ID: {}, 用户ID: {}", examId, userId);
            }
            return result;
        } catch (Exception e) {
            log.error("移除考试参与者失败", e);
            throw new BusinessException("移除考试参与者失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchRemoveParticipants(String examId, List<String> userIds) {
        try {
            int successCount = 0;
            for (String userId : userIds) {
                ExamParticipant participant = examParticipantMapper.selectByExamIdAndUserId(examId, userId);
                if (participant != null && removeById(participant.getId())) {
                    successCount++;
                }
            }

            log.info("批量移除考试参与者完成，考试ID: {}, 成功数量: {}/{}", examId, successCount, userIds.size());
            return successCount > 0;
        } catch (Exception e) {
            log.error("批量移除考试参与者失败", e);
            throw new BusinessException("批量移除考试参与者失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateParticipantStatus(String examId, String userId, Integer status) {
        try {
            ExamParticipant participant = examParticipantMapper.selectByExamIdAndUserId(examId, userId);
            if (participant == null) {
                throw new BusinessException("参与者不存在");
            }

            participant.setStatus(status);
            boolean result = updateById(participant);
            if (result) {
                log.info("更新参与者状态成功，考试ID: {}, 用户ID: {}, 状态: {}", examId, userId, status);
            }
            return result;
        } catch (Exception e) {
            log.error("更新参与者状态失败", e);
            throw new BusinessException("更新参与者状态失败: " + e.getMessage());
        }
    }

    @Override
    public List<ExamParticipant> getParticipantsByExamId(String examId) {
        return examParticipantMapper.selectByExamId(examId);
    }

    @Override
    public List<ExamParticipant> getParticipantsByUserId(String userId) {
        return examParticipantMapper.selectByUserId(userId);
    }

    @Override
    public IPage<ExamParticipant> getParticipantPage(Page<ExamParticipant> page, String examId, 
                                                    String userName, Integer status) {
        return examParticipantMapper.selectParticipantPage(page, examId, userName, status);
    }

    @Override
    public boolean canUserParticipate(String examId, String userId) {
        return examParticipantMapper.canUserParticipate(examId, userId);
    }

    @Override
    public Integer countParticipants(String examId, Integer status) {
        return examParticipantMapper.countByExamIdAndStatus(examId, status);
    }

    @Override
    public List<String> getParticipantUserIds(String examId) {
        return examParticipantMapper.selectUserIdsByExamId(examId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean clearParticipants(String examId) {
        try {
            int result = examParticipantMapper.deleteByExamId(examId);
            if (result > 0) {
                log.info("清空考试参与者成功，考试ID: {}, 清空数量: {}", examId, result);
            }
            return result > 0;
        } catch (Exception e) {
            log.error("清空考试参与者失败", e);
            throw new BusinessException("清空考试参与者失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean importParticipantsFromExcel(String examId, String filePath) {
        try {
            // 实现从Excel导入参与者的逻辑
            // 注意：这里是一个简化的实现，实际项目中需要使用EasyExcel或POI来读取Excel文件
            log.info("从Excel导入参与者，考试ID: {}, 文件路径: {}", examId, filePath);

            // 模拟读取Excel文件并解析用户信息
            // 实际实现中应该：
            // 1. 使用EasyExcel读取文件：EasyExcel.read(filePath, UserImportDTO.class, new UserImportListener()).sheet().doRead();
            // 2. 验证用户信息的有效性
            // 3. 批量添加参与者

            // 这里返回true表示导入成功，实际应该根据导入结果返回
            log.warn("Excel导入功能需要集成EasyExcel组件，当前为模拟实现");
            return true;
        } catch (Exception e) {
            log.error("从Excel导入参与者失败", e);
            throw new BusinessException("从Excel导入参与者失败: " + e.getMessage());
        }
    }

    @Override
    public String exportParticipantsToExcel(String examId) {
        try {
            // 实现导出参与者到Excel的逻辑
            // 1. 查询参与者列表
            List<ExamParticipant> participants = getParticipantsByExamId(examId);

            // 2. 生成Excel文件
            // 注意：这里是一个简化的实现，实际项目中需要使用EasyExcel来生成Excel文件
            // 实际实现中应该：
            // String fileName = "/tmp/participants_" + examId + "_" + System.currentTimeMillis() + ".xlsx";
            // EasyExcel.write(fileName, ParticipantExportDTO.class).sheet("参与者列表").doWrite(participants);

            String fileName = "/tmp/participants_" + examId + ".xlsx";
            log.info("导出参与者到Excel，考试ID: {}, 参与者数量: {}, 文件路径: {}", examId, participants.size(), fileName);
            log.warn("Excel导出功能需要集成EasyExcel组件，当前为模拟实现");

            // 3. 返回文件路径
            return fileName;
        } catch (Exception e) {
            log.error("导出参与者到Excel失败", e);
            throw new BusinessException("导出参与者到Excel失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean inviteUsers(String examId, List<String> userIds, String message) {
        try {
            // 批量添加参与者
            boolean result = batchAddParticipants(examId, userIds);
            
            if (result) {
                // 发送邀请通知
                // 注意：这里是一个简化的实现，实际项目中需要集成消息服务来发送通知
                // 实际实现中应该：
                // 1. 构造邀请消息
                // 2. 调用消息服务发送邮件或站内信
                // messageService.sendInvitation(userIds, examId, message);

                log.info("邀请用户参加考试成功，考试ID: {}, 用户数量: {}, 邀请消息: {}", examId, userIds.size(), message);
                log.warn("邀请通知功能需要集成消息服务，当前为模拟实现");
            }
            
            return result;
        } catch (Exception e) {
            log.error("邀请用户参加考试失败", e);
            throw new BusinessException("邀请用户参加考试失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean joinExam(String examId, String userId) {
        try {
            // 检查是否已经是参与者
            ExamParticipant existing = examParticipantMapper.selectByExamIdAndUserId(examId, userId);
            if (existing != null) {
                if (existing.getStatus() == 1) {
                    return true; // 已经是参与者
                } else {
                    throw new BusinessException("您被禁止参加此考试");
                }
            }

            // 自动加入考试（如果考试允许自由加入）
            String userName = UserContext.getUsername();
            return addParticipant(examId, userId, userName);
        } catch (Exception e) {
            log.error("加入考试失败", e);
            throw new BusinessException("加入考试失败: " + e.getMessage());
        }
    }

    @Override
    public boolean isUserParticipant(String examId, String userId) {
        try {
            LambdaQueryWrapper<ExamParticipant> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ExamParticipant::getExamId, examId)
                       .eq(ExamParticipant::getUserId, userId)
                       .eq(ExamParticipant::getStatus, 1); // 1表示正常状态

            long count = examParticipantMapper.selectCount(queryWrapper);
            return count > 0;
        } catch (Exception e) {
            log.error("检查用户是否在参与者列表中失败", e);
            return false;
        }
    }
}
